﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Toolkit;
using SharpDX.Toolkit.Graphics;
using SharpDX.IO;
using Texture2D = SharpDX.Direct3D11.Texture2D;


namespace Ignitron.EEngine.Adapters.DX.Graphics
{
    /// <summary>
    /// SharpDX Background
    /// </summary>
    internal class SharpDXBackground
    {
        /// <summary>
        /// The background providing class
        /// </summary>
        private IBackground mBackground;

        /// <summary>
        /// DX texture
        /// </summary>
        private Resource mResource;
        private ShaderResourceView mTexture;

        /// <summary>
        /// Device
        /// </summary>
        private Device mDevice;

        /// <summary>
        /// Batch for rendering 2D stuff
        /// </summary>
        private SpriteBatch mBatch;

        /// <summary>
        /// SharpDX Toolkit Device
        /// </summary>
        private GraphicsDevice mGraphicsDevice;

        /// <summary>
        /// Constructor
        /// </summary>
        public SharpDXBackground(IBackground background, Device device)
        {
            // set params
            mDevice = device;
            mBackground = background;

            mGraphicsDevice = GraphicsDevice.New(device);
            mGraphicsDevice.SetViewports(mDevice.ImmediateContext.Rasterizer.GetViewports()[0]);
            mBatch = new SpriteBatch(mGraphicsDevice);

            // convert image data
            int imageSize = mBackground.Width * mBackground.Height;
            byte[] image = new byte[imageSize * 4];
            int index = 0;
            for (int y = 0; y < mBackground.Height; y++)
            {
                for (int x = 0; x < mBackground.Width; x++)
                {
                    image[index++] = mBackground.Pixels[x, y, 2];
                    image[index++] = mBackground.Pixels[x, y, 1];
                    image[index++] = mBackground.Pixels[x, y, 0];
                    image[index++] = 255;
                }
            }

            Image dxImage = Image.New2D(mBackground.Width, mBackground.Height, MipMapCount.Auto, SharpDX.Toolkit.Graphics.PixelFormat.R8G8B8A8.UInt, 1);
            dxImage.PixelBuffer[0].SetPixels<byte>(image);

            mResource = new Texture2D(mDevice, new Texture2DDescription()            
            {
                ArraySize = 1,
                Width = mBackground.Width,
                Height = mBackground.Height,
                BindFlags = BindFlags.ShaderResource,
                CpuAccessFlags = CpuAccessFlags.Write,
                Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
                Usage = ResourceUsage.Dynamic,
                MipLevels = 1,
                OptionFlags = ResourceOptionFlags.None,
                SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0)
            }, dxImage.ToDataBox());


            mTexture = new ShaderResourceView(mDevice, mResource);
        }

        /// <summary>
        /// Shutsdown the background
        /// </summary>
        public void Shutdown()
        {
            if (mTexture != null)
            {
                mTexture.Dispose();
                mTexture = null;
            }
            if (mResource != null)
            {
                mResource.Dispose();
                mResource = null;
            }
            if (mBatch != null)
            {
                mBatch.Dispose();
                mBatch = null;
            }
            if (mGraphicsDevice != null)
            {
                mGraphicsDevice.Dispose();
                mGraphicsDevice = null;
            }
        }

        /// <summary>
        /// Background rendering method
        /// </summary>
        public void Render(int width, int height)
        {
            mGraphicsDevice.SetViewports(mDevice.ImmediateContext.Rasterizer.GetViewports()[0]);

            float hScale = Convert.ToSingle(width) / Convert.ToSingle(mBackground.Width);
            float vScale = Convert.ToSingle(height) / Convert.ToSingle(mBackground.Height);
            mBatch.Begin(SpriteSortMode.Texture, null);
            mBatch.Draw(mTexture, new Vector2(0, 0), null, Color.White,
                        0f, new Vector2(0, 0), new Vector2(hScale, vScale), SpriteEffects.None, 0);

            mBatch.End();
        }
    }
}
